package com.example.admin.bilibiliijkplayer.services;

import android.app.Service;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.SharedPreferences;
import android.media.AudioManager;
import android.net.Uri;
import android.os.IBinder;
import android.os.Message;
import android.os.PowerManager;
import android.os.RemoteException;
import android.preference.PreferenceManager;
import android.support.annotation.Nullable;
import android.telephony.TelephonyManager;
import android.text.TextUtils;
import android.util.Log;
import android.view.View;

import com.example.admin.bilibiliijkplayer.WeakHandler;
import com.example.admin.bilibiliijkplayer.application.Settings;
import com.example.admin.bilibiliijkplayer.interfaces.AudioAction;
import com.example.admin.bilibiliijkplayer.interfaces.IAudioService;
import com.example.admin.bilibiliijkplayer.interfaces.IAudioServiceCallback;

import java.io.IOException;
import java.util.HashMap;
import java.util.List;

import tv.danmaku.ijk.media.exo.IjkExoMediaPlayer;
import tv.danmaku.ijk.media.player.AndroidMediaPlayer;
import tv.danmaku.ijk.media.player.IMediaPlayer;
import tv.danmaku.ijk.media.player.IjkMediaPlayer;
import tv.danmaku.ijk.media.player.TextureMediaPlayer;

/**
 * 项目名称  ：Bilibili_ijkplayer
 * 类名称    ：
 * 类描述    ：
 * 创建人    ：Aman/862032054@qq.com
 * 创建时间  ：2016/10/19 14:05
 * 修改人    ：admin
 * 修改时间  ：2016/10/19 14:05
 * 修改备注  ：
 *
 * @version V1.0
 */
public class AudioService extends Service /*implements IAudioPlayerControl */ implements AudioAction {
    private static final String TAG = "KKPlayer/AudioService";
    private static final int SHOW_PROGRESS = 0;
    private static final int SHOW_TOAST = 1;
    public static final String START_FROM_NOTIFICATION = "from_notification";
    public static final String ACTION_REMOTE_GENERIC = "org.videolan.vlc.remote.";
    public static final String ACTION_REMOTE_BACKWARD = "org.videolan.vlc.remote.Backward";
    public static final String ACTION_REMOTE_PLAY = "org.videolan.vlc.remote.Play";
    public static final String ACTION_REMOTE_PLAYPAUSE = "org.videolan.vlc.remote.PlayPause";
    public static final String ACTION_REMOTE_PAUSE = "org.videolan.vlc.remote.Pause";
    public static final String ACTION_REMOTE_STOP = "org.videolan.vlc.remote.Stop";
    public static final String ACTION_REMOTE_FORWARD = "org.videolan.vlc.remote.Forward";
    public static final String ACTION_REMOTE_LAST_PLAYLIST = "org.videolan.vlc.remote.LastPlaylist";
    public static final String ACTION_WIDGET_INIT = "org.videolan.vlc.widget.INIT";
    public static final String ACTION_WIDGET_UPDATE = "org.videolan.vlc.widget.UPDATE";
    public static final String ACTION_WIDGET_UPDATE_COVER = "org.videolan.vlc.widget.UPDATE_COVER";
    public static final String ACTION_WIDGET_UPDATE_POSITION = "org.videolan.vlc.widget.UPDATE_POSITION";

    public static final String WIDGET_PACKAGE = "org.videolan.vlc";
    public static final String WIDGET_CLASS = "org.videolan.vlc.widget.VLCAppWidgetProvider";

    public final static String SLEEP_INTENT = "org.videolan.vlc.SleepIntent";

    //TODO 初始化
    private HashMap<IAudioServiceCallback, Integer> mCallback;
    private Settings mSettings;
    private IMediaPlayer mMediaPlayer;

    private PowerManager.WakeLock mWakeLock;
    private boolean mDetectHeadset = true;
    private AudioServiceEventHandler mHandler = new AudioServiceEventHandler(this);

    /**
     * 每个1秒检查播放情况
     */
    private final static int MSG_CHECK_UPDATA = 1;

    @Override
    public void onCreate() {
        super.onCreate();

        mCallback = new HashMap<IAudioServiceCallback, Integer>();
        mSettings = new Settings(this);

        // Make sure the audio player will acquire a wake-lock while playing. If we don't do
        // that, the CPU might go to sleep while the song is playing, causing playback to stop.
        PowerManager pm = (PowerManager) getSystemService(Context.POWER_SERVICE);
        mWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, TAG);

        IntentFilter filter = new IntentFilter();
        filter.setPriority(Integer.MAX_VALUE);
        filter.addAction(ACTION_REMOTE_BACKWARD);
        filter.addAction(ACTION_REMOTE_PLAYPAUSE);
        filter.addAction(ACTION_REMOTE_PLAY);
        filter.addAction(ACTION_REMOTE_PAUSE);
        filter.addAction(ACTION_REMOTE_STOP);
        filter.addAction(ACTION_REMOTE_FORWARD);
        filter.addAction(ACTION_REMOTE_LAST_PLAYLIST);
        filter.addAction(ACTION_WIDGET_INIT);
        filter.addAction(Intent.ACTION_HEADSET_PLUG);
        filter.addAction(AudioManager.ACTION_AUDIO_BECOMING_NOISY);
        filter.addAction(SLEEP_INTENT);
        registerReceiver(serviceReceiver, filter);

        final SharedPreferences pref = PreferenceManager.getDefaultSharedPreferences(this);
        boolean stealRemoteControl = pref.getBoolean("enable_steal_remote_control", false);

    }

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        //updateWidget(this);
        return super.onStartCommand(intent, flags, startId);
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
        stop();
        if (mWakeLock.isHeld())
            mWakeLock.release();
        unregisterReceiver(serviceReceiver);
//        if (mRemoteControlClientReceiver != null) {
//            unregisterReceiver(mRemoteControlClientReceiver);
//            mRemoteControlClientReceiver = null;
//        }
    }

    @Nullable
    @Override
    public IBinder onBind(Intent intent) {
        return mInterface;
    }

    public IMediaPlayer createPlayer(Uri uri, int playerType) {
        IMediaPlayer mediaPlayer = null;

        switch (playerType) {
            case Settings.PV_PLAYER__IjkExoMediaPlayer: {
                IjkExoMediaPlayer IjkExoMediaPlayer = new IjkExoMediaPlayer(this.getApplicationContext());
                mediaPlayer = IjkExoMediaPlayer;
            }
            break;
            case Settings.PV_PLAYER__AndroidMediaPlayer: {
                AndroidMediaPlayer androidMediaPlayer = new AndroidMediaPlayer();
                mediaPlayer = androidMediaPlayer;
            }
            break;
            case Settings.PV_PLAYER__IjkMediaPlayer:
            default: {
                IjkMediaPlayer ijkMediaPlayer = null;
                if (uri != null) {
                    ijkMediaPlayer = new IjkMediaPlayer();
                    ijkMediaPlayer.native_setLogLevel(IjkMediaPlayer.IJK_LOG_DEBUG);
                    if (mSettings.getUsingMediaCodec()) {
                        ijkMediaPlayer.setOption(IjkMediaPlayer.OPT_CATEGORY_PLAYER, "mediacodec", 1);
                        if (mSettings.getUsingMediaCodecAutoRotate()) {
                            ijkMediaPlayer.setOption(IjkMediaPlayer.OPT_CATEGORY_PLAYER, "mediacodec-auto-rotate", 1);
                        } else {
                            ijkMediaPlayer.setOption(IjkMediaPlayer.OPT_CATEGORY_PLAYER, "mediacodec-auto-rotate", 0);
                        }
                        if (mSettings.getMediaCodecHandleResolutionChange()) {
                            ijkMediaPlayer.setOption(IjkMediaPlayer.OPT_CATEGORY_PLAYER, "mediacodec-handle-resolution-change", 1);
                        } else {
                            ijkMediaPlayer.setOption(IjkMediaPlayer.OPT_CATEGORY_PLAYER, "mediacodec-handle-resolution-change", 0);
                        }
                    } else {
                        ijkMediaPlayer.setOption(IjkMediaPlayer.OPT_CATEGORY_PLAYER, "mediacodec", 0);
                    }

                    if (mSettings.getUsingOpenSLES()) {
                        ijkMediaPlayer.setOption(IjkMediaPlayer.OPT_CATEGORY_PLAYER, "opensles", 1);
                    } else {
                        ijkMediaPlayer.setOption(IjkMediaPlayer.OPT_CATEGORY_PLAYER, "opensles", 0);
                    }

                    String pixelFormat = mSettings.getPixelFormat();
                    if (TextUtils.isEmpty(pixelFormat)) {
                        ijkMediaPlayer.setOption(IjkMediaPlayer.OPT_CATEGORY_PLAYER, "overlay-format", IjkMediaPlayer.SDL_FCC_RV32);
                    } else {
                        ijkMediaPlayer.setOption(IjkMediaPlayer.OPT_CATEGORY_PLAYER, "overlay-format", pixelFormat);
                    }
                    ijkMediaPlayer.setOption(IjkMediaPlayer.OPT_CATEGORY_PLAYER, "framedrop", 1);
                    ijkMediaPlayer.setOption(IjkMediaPlayer.OPT_CATEGORY_PLAYER, "start-on-prepared", 0);

                    ijkMediaPlayer.setOption(IjkMediaPlayer.OPT_CATEGORY_FORMAT, "http-detect-range-support", 0);

                    ijkMediaPlayer.setOption(IjkMediaPlayer.OPT_CATEGORY_CODEC, "skip_loop_filter", 48);
                }
                mediaPlayer = ijkMediaPlayer;
            }
            break;
        }

        if (mSettings.getEnableDetachedSurfaceTextureView()) {
            mediaPlayer = new TextureMediaPlayer(mediaPlayer);
        }

        return mediaPlayer;
    }

    private final BroadcastReceiver serviceReceiver = new BroadcastReceiver() {
        @Override
        public void onReceive(Context context, Intent intent) {
            String action = intent.getAction();
            int state = intent.getIntExtra("state", 0);
            if (mMediaPlayer == null) {
                Log.w(TAG, "Intent received, but VLC is not loaded, skipping.");
                return;
            }

            // skip all headsets events if there is a call
            TelephonyManager telManager = (TelephonyManager) getSystemService(Context.TELEPHONY_SERVICE);
            if (telManager != null && telManager.getCallState() != TelephonyManager.CALL_STATE_IDLE)
                return;

            /*
             * Launch the activity if needed
             */
            if (action.startsWith(ACTION_REMOTE_GENERIC) && !mMediaPlayer.isPlaying() && !hasCurrentMedia()) {
//                Intent iVlc = new Intent(context, MainActivity.class);
//                iVlc.putExtra(START_FROM_NOTIFICATION, true);
//                iVlc.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_SINGLE_TOP);
//                context.startActivity(iVlc);
            }

            /*
             * Remote / headset control events
             */
            if (action.equalsIgnoreCase(ACTION_REMOTE_PLAYPAUSE)) {
                if (mMediaPlayer.isPlaying() && hasCurrentMedia())
                    pause();
                else if (!mMediaPlayer.isPlaying() && hasCurrentMedia())
                    play();
            } else if (action.equalsIgnoreCase(ACTION_REMOTE_PLAY)) {
                if (!mMediaPlayer.isPlaying() && hasCurrentMedia())
                    play();
            } else if (action.equalsIgnoreCase(ACTION_REMOTE_PAUSE)) {
                if (mMediaPlayer.isPlaying() && hasCurrentMedia())
                    pause();
            } else if (action.equalsIgnoreCase(ACTION_REMOTE_STOP)) {
                stop();
            }/* else if (action.equalsIgnoreCase(ACTION_REMOTE_LAST_PLAYLIST)) {
                loadLastPlaylist();
            } */

            /*
             * headset plug events
             */
            if (mDetectHeadset) {
                if (action.equalsIgnoreCase(AudioManager.ACTION_AUDIO_BECOMING_NOISY)) {
                    Log.i(TAG, "Headset Removed.");
                    if (mMediaPlayer.isPlaying() && hasCurrentMedia())
                        pause();
                } else if (action.equalsIgnoreCase(Intent.ACTION_HEADSET_PLUG) && state != 0) {
                    Log.i(TAG, "Headset Inserted.");
                    if (!mMediaPlayer.isPlaying() && hasCurrentMedia())
                        play();
                }
            }

            /*
             * Sleep
             */
            if (action.equalsIgnoreCase(SLEEP_INTENT)) {
                stop();
            }
        }
    };

    //TODO
    private boolean hasCurrentMedia() {
        return true;
    }


    private void executeUpdate() {
        mHandler.sendEmptyMessage(MSG_CHECK_UPDATA);
        //executeUpdate(true);
    }

    private void executeComplete() {
        for (IAudioServiceCallback callback : mCallback.keySet()) {
            try {
                callback.onCompletion();
            } catch (RemoteException e) {
                e.printStackTrace();
            }
        }
    }

    private void executeError(int i, int i1) {
        for (IAudioServiceCallback callback : mCallback.keySet()) {
            try {
                callback.onError(i, i1);
            } catch (RemoteException e) {
                e.printStackTrace();
            }
        }
    }

    private void executeUpdate(Boolean updateWidget) {
        for (IAudioServiceCallback callback : mCallback.keySet()) {
            try {
                callback.update();
            } catch (RemoteException e) {
                e.printStackTrace();
            }
        }
//        if (updateWidget)
//            updateWidget(this);
    }


    private final IAudioService.Stub mInterface = new IAudioService.Stub() {

        @Override
        public String getCurrentMediaLocation() throws RemoteException {
            //return mLibVLC.getMediaList().getMRL(mCurrentIndex);
            //return mMediaPlayer.getDataSource();
            return AudioService.this.getCurrentMediaLocation();
        }

        @Override
        public void pause() throws RemoteException {
            //AudioService.this.pause();
            AudioService.this.pause();
        }

        @Override
        public void play() throws RemoteException {
            //AudioService.this.play();
            AudioService.this.play();
        }

        //TODO
        @Override
        public void stop() throws RemoteException {
            AudioService.this.stop();
        }

        @Override
        public void seekTo(long time) throws RemoteException {
            AudioService.this.seekTo(time);
        }

        @Override
        public boolean isPlaying() throws RemoteException {
            //return mLibVLC.isPlaying();
            //return mMediaPlayer.isPlaying();
            return AudioService.this.isPlaying();
        }


        @Override
        public synchronized void addAudioCallback(IAudioServiceCallback cb)
                throws RemoteException {
            Integer count = mCallback.get(cb);
            if (count == null)
                count = 0;
            mCallback.put(cb, count + 1);
        }

        @Override
        public synchronized void removeAudioCallback(IAudioServiceCallback cb)
                throws RemoteException {
            Integer count = mCallback.get(cb);
            if (count == null)
                count = 0;
            if (count > 1)
                mCallback.put(cb, count - 1);
            else
                mCallback.remove(cb);
        }

        @Override
        public void detectHeadset(boolean enable) throws RemoteException {
            mDetectHeadset = enable;
        }

        @Override
        public long getTime() throws RemoteException {
            //return (int) mLibVLC.getTime();
            return AudioService.this.getTime();
        }

        @Override
        public long getLength() throws RemoteException {
            //return (int) mLibVLC.getLength();
            return AudioService.this.getLength();
        }

        /**
         * Loads a selection of files (a non-user-supplied collection of media)
         * into the primary or "currently playing" playlist.
         *
         * @param mediaPathList A list of locations to load
         * @param position The position to start playing at
         * @throws RemoteException
         */
        @Override
        public void load(List<String> mediaPathList, int position)
                throws RemoteException {
            AudioService.this.load(mediaPathList, position, null);
        }


//        @Override
//        public void setTime(long time) throws RemoteException {
//            //mLibVLC.setTime(time);
//            AudioService.this.seekTo(time);
//        }
    };

    @Override
    public void pause() {
        mMediaPlayer.pause();
    }

    @Override
    public boolean isPlaying() {
        return mMediaPlayer.isPlaying();
    }

    @Override
    public String getCurrentMediaLocation() {
        return mMediaPlayer.getDataSource();
    }

    @Override
    public void load(List<String> mediaPathList, int position, View bindView) {
        IjkMediaPlayer.loadLibrariesOnce(null);
        IjkMediaPlayer.native_profileBegin("libijkplayer.so");
        Uri uri = Uri.parse(mediaPathList.get(0));
        mMediaPlayer = createPlayer(uri, 1);
        try {
            mMediaPlayer.setDataSource(uri.toString());
            MediaPlayerService.intentToStart(this);
            MediaPlayerService.setMediaPlayer(mMediaPlayer);
            mMediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);
            mMediaPlayer.setScreenOnWhilePlaying(true);
            mMediaPlayer.prepareAsync();
            mMediaPlayer.setOnPreparedListener(new IMediaPlayer.OnPreparedListener() {
                // 当prepare完成后，该方法触发，在这里我们播放视频
                @Override
                public void onPrepared(IMediaPlayer iMediaPlayer) {
                    mMediaPlayer.start();
                    executeUpdate();
                }
            });
            mMediaPlayer.setOnInfoListener(new IMediaPlayer.OnInfoListener() {
                // 当一些特定信息出现或者警告时触发
                @Override
                public boolean onInfo(IMediaPlayer iMediaPlayer, int i, int i1) {
                    return false;
                }
            });
            mMediaPlayer.setOnBufferingUpdateListener(new IMediaPlayer.OnBufferingUpdateListener() {
                @Override
                public void onBufferingUpdate(IMediaPlayer iMediaPlayer, int i) {

                }
            });
            mMediaPlayer.setOnErrorListener(new IMediaPlayer.OnErrorListener() {
                @Override
                public boolean onError(IMediaPlayer iMediaPlayer, int i, int i1) {
                    executeError(i, i1);
                    return false;
                }
            });
            mMediaPlayer.setOnCompletionListener(new IMediaPlayer.OnCompletionListener() {
                // 当MediaPlayer播放完成后触发
                @Override
                public void onCompletion(IMediaPlayer iMediaPlayer) {
                    executeComplete();
                }
            });
            mMediaPlayer.setOnSeekCompleteListener(new IMediaPlayer.OnSeekCompleteListener() {
                @Override
                public void onSeekComplete(IMediaPlayer iMediaPlayer) {

                }
            });

        } catch (IOException e) {
            e.printStackTrace();
        }
        //TODO 这里要处理各种错误情况
    }

    @Override
    public long getLength() {
        return mMediaPlayer.getDuration();
    }

    @Override
    public long getTime() {
        return mMediaPlayer.getCurrentPosition();
    }

    @Override
    public void seekTo(long time) {
        try {
            mMediaPlayer.seekTo(time);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    //TODO 最好判断下状态
    @Override
    public void play() {
        mMediaPlayer.start();
    }

    @Override
    public void stop() {
        mMediaPlayer.stop();
    }


    private static class AudioServiceEventHandler extends WeakHandler<AudioService> {
//        private final static int MSG_CHECK_UPDATE = 1;
//        private final static int MSG_CHECK_COMPLETE = 2;
//        private final static int MSG_CHECK_ERROE = 3;

        public AudioServiceEventHandler(AudioService fragment) {
            super(fragment);
        }

        @Override
        public void handleMessage(Message msg) {
            AudioService service = getOwner();
            if (service == null) return;
            service.executeUpdate(true);
            postDelayed(new Runnable() {
                @Override
                public void run() {
                    sendEmptyMessage(MSG_CHECK_UPDATA);
                }
            }, 1000);
//            switch (msg.getData().getInt("event")) {
//
//                default:
//                    Log.e(TAG, "Event not handled");
//                    break;
//            }
        }
    }

}
